package utils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import persistencia.Archivo;
import persistencia.Register;
import config.ConfigManager;
import exception.InvalidConfigException;

public class PhysicalFileManaging {
	private String directoriesListFileName;
	private String filesListFileName;
	private Archivo fileOfDirectories;
	private Archivo fileOfFiles;
	private long numberOfDirectoryRegisters;
	private long numberOfFileRegisters;
	private long currentFileIndex;
	private long currentDirectoryIndex;
	private boolean fileCorrupted;

	public PhysicalFileManaging() {
		this.currentDirectoryIndex = 0;
		this.currentFileIndex = 0;
		fileCorrupted = false;
		directoriesListFileName = getDirectoriesFileListName();
		filesListFileName = getFilesFileListName();
		initialize();
	}

	public void initialize() {
		try {
			initializeDirectory();
			initializeFile();
			// indicar total de dirs
			// indicar total de files
		} catch (Exception ex) {
			ex.printStackTrace();
			fileCorrupted = true;
		}
	}

	private void initializeDirectory() throws ClassNotFoundException, IOException, Exception {
		createFileOfDirectories();
		if (this.fileOfDirectories != null && this.fileOfDirectories.getFileDescriptor().exists()) {
			fileOfDirectories.cleanupFile();
			if (numberOfDirectoryRegisters > 0) {
				numberOfDirectoryRegisters = fileOfDirectories.countRegisters();
			}
		}
	}

	private void initializeFile() throws ClassNotFoundException, IOException, Exception {
		createFileOfFiles();
		if (this.fileOfFiles != null && this.fileOfFiles.getFileDescriptor().exists()) {
			fileOfFiles.cleanupFile();
			if (numberOfFileRegisters > 0) {
				numberOfFileRegisters = fileOfFiles.countRegisters();
			}
		}
	}

	/**
	 * Creates the fileOfDirectories descriptor
	 */
	private void createFileOfDirectories() throws ClassNotFoundException, IOException {
		fileOfDirectories = new Archivo(directoriesListFileName, new FileRegister());
	}

	private void createFileOfFiles() throws ClassNotFoundException, IOException {
		fileOfFiles = new Archivo(filesListFileName, new FileRegister());
	}

	/**
	 * Creates or open the fileOfDirectories, in the first register
	 */
	public void openDirectoryFile() throws IOException {
		this.fileOfDirectories.openForReadWrite();
	}

	/**
	 * Closes the fileOfDirectories
	 */
	public void closeDirectoryFile() throws IOException {
		this.fileOfDirectories.close();
	}

	/**
	 * Add a single directory to the fileOfDirectories
	 * @param dir
	 * @return
	 */
	public boolean add(File file) {
		boolean flag = false;
		FileRegister fr = new FileRegister(file.getAbsolutePath());
		flag = writeNewFileRegister(fr, file.isDirectory());
		return flag;
	}

	/**
	 * Add a collection of directories to the fileOfDirectories
	 * @param dirs
	 */
	public void add(ArrayList<File> files) {
		for (File file : files) {
			add(file);
		}
	}

	/**
	 * Add a new register to fileOfDirectories or to fileOfFiles, depending on if the
	 * current file is a directory or not, with the name file/directory
	 * @param fr
	 * @return
	 */
	private boolean writeNewFileRegister(FileRegister fr, boolean isDirectory) {
		boolean flag = false;
		if (isDirectory) {
			if (flag = fileOfDirectories.altaDirecta(new Register(fr)))
				this.numberOfDirectoryRegisters++;
		} else {
			if (flag = fileOfFiles.altaDirecta(new Register(fr)))
				this.numberOfFileRegisters++;
		}
		return flag;
	}

	/**
	 * Returns the next directory to be processed
	 * @return dir, the first non-deleted directory in the fileOfDirectories
	 */
	public File getNextDirectory() {
		File dir = null;
		if (numberOfDirectoryRegisters > 0) {
			try {
				fileOfDirectories.openForRead();
				fileOfDirectories.seekRegister(currentDirectoryIndex);
				String filePath = ((FileRegister) (fileOfDirectories.leer().getData())).getFilePath();
				dir = new File(filePath);
				fileOfDirectories.close();
			} catch (IOException ex) {
				ex.printStackTrace();
				System.out.println("Error al acceder al archivo: " + ex.getMessage());
			}
		}
		return dir;
	}

	public File getNextFile() {
		File file = null;
		if (numberOfFileRegisters > 0) {
			try {
				fileOfFiles.openForRead();
				fileOfDirectories.seekRegister(currentFileIndex);
				System.out.println("register: " + fileOfDirectories.registerPos());
				System.out.println("\nbyte: " + fileOfFiles.bytePos());
				String filePath = ((FileRegister) (fileOfFiles.leer().getData())).getFilePath();
				file = new File(filePath);
				fileOfFiles.close();
			} catch (IOException ex) {
				ex.printStackTrace();
				System.out.println("Error al acceder al archivo: " + ex.getMessage());
			}
		}
		return file;
	}

	public void deleteDirectory(File dir) {
		boolean flag = fileOfDirectories.baja(currentDirectoryIndex);
		if (flag) {
			currentDirectoryIndex++;
			numberOfDirectoryRegisters--;
		}
	}

	public void deleteFile(File file) {
		boolean flag = fileOfFiles.baja(currentFileIndex);
		if (flag) {
			currentFileIndex++;
			numberOfFileRegisters--;
		}
	}

	public boolean isFileCorrupted() {
		return fileCorrupted;
	}

	public void setFileCorrupted(boolean fileCorrupted) {
		this.fileCorrupted = fileCorrupted;
	}

	public long getNumberOfDirectoryRegisters() {
		return numberOfDirectoryRegisters;
	}

	public long getNumberOfFilesRegisters() {
		return numberOfFileRegisters;
	}

	private String getDirectoriesFileListName() {
		String fileName = "";
		try {
			fileName = ConfigManager.getStringConfig("directories_list_name");
		} catch (InvalidConfigException ex) {
			ex.printStackTrace();
			System.out.println("Directories File List Name: " + ex.getMessage());
		}
		return fileName;
	}

	private String getFilesFileListName() {
		String fileName = "";
		try {
			fileName = ConfigManager.getStringConfig("files_list_name");
		} catch (InvalidConfigException ex) {
			ex.printStackTrace();
			System.out.println("Files File List Name: " + ex.getMessage());
		}
		return fileName;
	}
}
